package br.com.diego.system.manager.usuario.impl;

import br.com.diego.system.controller.consultausuario.ConsultaUsuarioVo;
import br.com.diego.system.controller.consultausuario.SituacaoVo;
import br.com.diego.system.controller.consultausuario.TipoConsultaVo;
import br.com.diego.system.controller.consultausuario.TipoVo;
import br.com.diego.system.manager.AbstractDiegoManager;
import br.com.diego.system.entity.usuario.Usuario;
import br.com.diego.system.manager.usuario.UsuarioManager;
import javax.persistence.NoResultException;
import java.util.List;
import javax.persistence.OptimisticLockException;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.transaction.annotation.Transactional;

public class JpaUsuarioManagerImpl extends AbstractDiegoManager implements UsuarioManager {

    @Override
    @Transactional(readOnly = false)
    public void salvar(Usuario usuario) {
        if (usuario.getId() == null) {
            try {
                entityManager.persist(usuario);                
            }catch(IllegalArgumentException e) {
                throw new IllegalArgumentException(
                        "Não foi possível Salvar: Erro: " + e);
            }            
        } else {
            try {
                entityManager.merge(usuario);
            } catch (OptimisticLockException e) {
                throw new IllegalArgumentException(
                        "Estes dados foram alterados por outro usuario.");
            }
        }
    }

    @Override
    @Transactional(readOnly = false)
    public void deletar(Usuario usuario) {
        usuario = buscarPeloId(usuario.getId());
        entityManager.remove(usuario);
    }

    @Override
    @Transactional(readOnly = true)
    public Usuario verificaEmailUnico(Usuario usuario) {
        Session session = (Session) entityManager.getDelegate();
        Criteria criteria = session.createCriteria(Usuario.class)
                .add(Restrictions.eq("email", usuario.getEmail()));
        if (usuario.getId() != null) {
            criteria.add(Restrictions.ne("id", usuario.getId()));
        }

        try {
            return (Usuario) criteria.uniqueResult();
        } catch (NoResultException e) {
            return null;
        }
    }

    @Override
    @Transactional(readOnly = true)
    public Usuario verificaSenhaCorreta(Usuario usuario) {
        Session session = (Session) entityManager.getDelegate();
        Criteria criteria = session.createCriteria(Usuario.class)
                .add(Restrictions.eq("id", usuario.getId()))
                .add(Restrictions.eq("senha", usuario.getSenha()));

        try {
            return (Usuario) criteria.uniqueResult();
        } catch (NoResultException e) {
            return null;
        }
    }

    @Override
    @Transactional(readOnly = true)
    public Usuario buscarPeloId(Long id) {
        return entityManager.find(Usuario.class, id);
    }

    @Override
    @Transactional(readOnly = true)
    public List<Usuario> consultar(ConsultaUsuarioVo consultaUsuarioVo) {
        Session session = (Session) entityManager.getDelegate();
        Criteria criteria = session.createCriteria(Usuario.class);

        if (consultaUsuarioVo.getTipoConsultaVo() == TipoConsultaVo.ID) {
            try {
                criteria.add(Restrictions.eq("id", Long.valueOf(consultaUsuarioVo.getFiltro())));
            } catch (IllegalArgumentException e) {
                throw new IllegalArgumentException("Valor informado invalido");
            }
        } else if (consultaUsuarioVo.getTipoConsultaVo() == TipoConsultaVo.NOME) {
            criteria.add(Restrictions.ilike("nome", String.format("%%%s%%", consultaUsuarioVo.getFiltro())));
            criteria.addOrder(Order.asc("nome"));
        } else if (consultaUsuarioVo.getTipoConsultaVo() == TipoConsultaVo.EMAIL) {
            criteria.add(Restrictions.ilike("email", String.format("%%%s%%", consultaUsuarioVo.getFiltro())));
            criteria.addOrder(Order.asc("email"));
        } else if (consultaUsuarioVo.getTipoConsultaVo() == TipoConsultaVo.NOME_EMAIL) {
            criteria.add(Restrictions.or(
                    Restrictions.ilike("nome", String.format("%%%s%%", consultaUsuarioVo.getFiltro())),
                    Restrictions.ilike("email", String.format("%%%s%%", consultaUsuarioVo.getFiltro()))));
            criteria.addOrder(Order.asc("nome"));
        } else {
            criteria.addOrder(Order.asc("nome"));
        }

        if (consultaUsuarioVo.getSituacaoVo() != SituacaoVo.TODOS) {
            criteria.add(Restrictions.eq("situacao", consultaUsuarioVo.getSituacaoVo()));
        }

        if (consultaUsuarioVo.getTipoVo() != TipoVo.TODOS) {
            criteria.add(Restrictions.eq("tipo", consultaUsuarioVo.getTipoVo()));
        }
        return criteria.list();
    }
}
